﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XboxUserInterface.Keys;
using XboxUserInterface.Variables;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using System.Globalization;
using System.Windows.Forms;
using System.Reflection;

namespace XboxUserInterface.Settings
{
    /// <summary>
    /// This class houses assorted operations for handling KeyMaps, including reading and writing them to xml.
    /// </summary>
    public static class Operations
    {
        /// <summary>
        /// Loads all schemes contained in the provided xml file into <c>Globals.Schemes</c>
        /// </summary>
        /// <param name="fileLoc">Location of the xml file to load data from</param>
        /// <returns>The list of KeyMaps that were added to <c>Globals.Schemes</c></returns>
        public static List<KeyMap> loadAllSchemes(string fileLoc)
        {
            KeyMap activeMap = null;

            if (File.Exists(fileLoc))
            {
                try
                {
                    //XElement xml = XDocument.Load(XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream("XboxUserInterface.schemes.xml"))).Element("Schemes");
                    XElement xml = XDocument.Load(fileLoc).Element("Schemes");
                    var schemes = xml.Descendants(XName.Get("Scheme"));

                    foreach (XElement e in schemes)
                    {
                        KeyMap m = new KeyMap(e.Attribute("name").Value);
                        if (e.Attribute(XName.Get("active")).Value.ToLower() == "true")
                            activeMap = m;

                        var keys = e.Descendants(XName.Get("Key"));

                        foreach (XElement k in keys)
                        {
                            m.Keys.Add(new Key(
                                (KeyboardFunction)Enum.Parse(typeof(KeyboardFunction), k.Element(XName.Get("function")).Value),
                                (ControllerButtons)Enum.Parse(typeof(ControllerButtons), k.Element(XName.Get("xboxKey")).Value))
                                );
                        }

                        Globals.Schemes.Add(m);
                    }
                }
                catch
                {
                    MessageBox.Show("Could not load saved schemes.  Loading default scheme.");
                    Globals.Schemes.Add(KeyMap.Default);
                    activeMap = Globals.Schemes[0];
                }
            }

            else
            {
                File.Create(Application.StartupPath + "\\Resources\\schemes.xml");
                Globals.Schemes.Add(KeyMap.Default);
                activeMap = Globals.Schemes[0];

                Operations.SaveGlobalSchemes();
            }

            Globals.Active = activeMap;
            Operations.SaveGlobalSchemes();

            return Globals.Schemes;
        }

        /// <summary>
        /// Checks <c>Globals.Schemes</c> to see if a map is included, and if it is not, adds it to the list.
        /// </summary>
        /// <param name="map">KeyMap to add to the list</param>
        /// <returns>The list of KeyMaps in <c>Globals.Schemes</c></returns>
        public static List<KeyMap> AddScheme(KeyMap map)
        {
            foreach (KeyMap m in Globals.Schemes)
            {
                if (m.Equals(map))
                    return Globals.Schemes;
            }

            Globals.Schemes.Add(map);
            return Globals.Schemes;
        }
        
        /// <summary>
        /// Removes a given map from <c>Globals.Schemes</c> if it exists.
        /// </summary>
        /// <param name="map">KeyMap to remove</param>
        /// <returns>The list of KeyMaps in <c>Globals.Schemes</c></returns>
        public static List<KeyMap> RemoveScheme(KeyMap map)
        {
            for(int i =0; i< Globals.Schemes.Count;i++)
            {
                if (Globals.Schemes[i].Equals(map))
                {
                    Globals.Schemes.RemoveAt(i);
                    break;
                }
            }

            return Globals.Schemes;
        }

        /// <summary>
        /// Writes all schemes currently in <c>Globals.Schemes</c> to an xml file called "schemes.xml" in the executable directory.
        /// </summary>
        /// <returns>Whether or not the operation succeded</returns>
        public static bool SaveGlobalSchemes()
        {
            bool completed = false;

            XmlWriter w = XmlWriter.Create(Application.StartupPath + "\\schemes.xml",
                                            new XmlWriterSettings
                                            {
                                                Indent = true,
                                                Encoding = System.Text.Encoding.UTF8,
                                                CloseOutput = true
                                            });

            try
            {
                w.WriteStartDocument(true);
                w.WriteStartElement("Schemes");
                foreach (KeyMap m in Globals.Schemes)
                {
                    w.WriteStartElement("Scheme");
                    w.WriteAttributeString("name", m.SchemeName);
                    w.WriteAttributeString("active", m.Active.ToString());

                    foreach (Key k in m.Keys)
                    {
                        w.WriteStartElement("Key");
                        w.WriteElementString("xboxKey", k.GamePadKey.ToString());
                        w.WriteElementString("function", k.KeyCode.ToString());
                        w.WriteEndElement();
                    }

                    w.WriteEndElement();
                }
                w.WriteEndElement();
                w.WriteEndDocument();
                w.Flush();

                completed = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                completed = false;
            }
            w.Close();
            return completed;
        }
        
        /// <summary>
        /// Adds a default scheme to the list of schemes
        /// </summary>
        public static void addDefaultScheme()
        {
            Globals.Schemes.Add(KeyMap.Default);
        }

        /// <summary>
        /// Sets the given map as active in <c>Globals</c>
        /// </summary>
        /// <param name="map">KeyMap to set as active</param>
        public static void SetActiveScheme(KeyMap map)
        {
            Globals.Active = map;
        }
    }
}
